// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

import 'chrome://resources/cr_components/managed_dialog/managed_dialog.js';
import 'chrome://resources/cr_elements/cr_button/cr_button.m.js';
import 'chrome://resources/cr_elements/cr_link_row/cr_link_row.js';
import 'chrome://resources/cr_elements/shared_style_css.m.js';
import 'chrome://resources/cr_elements/md_select_css.m.js';
import '../controls/controlled_radio_button.js';
import '../controls/extension_controlled_indicator.js';
import '../controls/settings_radio_group.js';
import '../controls/settings_toggle_button.js';
import '../settings_page/settings_animated_pages.js';
import '../settings_page/settings_subpage.js';
import '../settings_shared_css.js';
import '../settings_vars_css.js';
import './home_url_input.js';
import '../controls/settings_dropdown_menu.js';

import {assert} from 'chrome://resources/js/assert.m.js';
import {I18nMixin} from 'chrome://resources/js/i18n_mixin.js';
import {html, PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';

import {BaseMixin} from '../base_mixin.js';
import {DropdownMenuOptionList} from '../controls/settings_dropdown_menu.js';
import {SettingsDropdownMenuElement} from '../controls/settings_dropdown_menu.js';
import {loadTimeData} from '../i18n_setup.js';
import {AppearancePageVisibility} from '../page_visibility.js';
import {PrefsMixin} from '../prefs/prefs_mixin.js';
import {routes} from '../route.js';
import {Router} from '../router.js';

import {AppearanceBrowserProxy, AppearanceBrowserProxyImpl} from './appearance_browser_proxy.js';


/**
 * This is the absolute difference maintained between standard and
 * fixed-width font sizes. http://crbug.com/91922.
 */
const SIZE_DIFFERENCE_FIXED_STANDARD: number = 3;

/**
 * ID for autogenerated themes. Should match
 * |ThemeService::kAutogeneratedThemeID|.
 */
const AUTOGENERATED_THEME_ID: string = 'autogenerated_theme_id';

/**
 * 'settings-appearance-page' is the settings page containing appearance
 * settings.
 */

export interface SettingsAppearancePageElement {
  $: {
    defaultFontSize: SettingsDropdownMenuElement,
    zoomLevel: HTMLSelectElement,
  };
}

const SettingsAppearancePageElementBase =
    I18nMixin(PrefsMixin(BaseMixin(PolymerElement)));

export class SettingsAppearancePageElement extends
    SettingsAppearancePageElementBase {
  static get is() {
    return 'settings-appearance-page';
  }

  static get template() {
    return html`{__html_template__}`;
  }

  static get properties() {
    return {
      /**
       * Dictionary defining page visibility.
       */
      pageVisibility: Object,

      prefs: {
        type: Object,
        notify: true,
      },

      defaultZoom_: Number,

      isWallpaperPolicyControlled_: {type: Boolean, value: true},

      /**
       * List of options for the font size drop-down menu.
       */
      fontSizeOptions_: {
        readOnly: true,
        type: Array,
        value() {
          return [
            {value: 9, name: loadTimeData.getString('verySmall')},
            {value: 12, name: loadTimeData.getString('small')},
            {value: 16, name: loadTimeData.getString('medium')},
            {value: 20, name: loadTimeData.getString('large')},
            {value: 24, name: loadTimeData.getString('veryLarge')},
          ];
        },
      },

      /**
       * Predefined zoom factors to be used when zooming in/out. These are in
       * ascending order. Values are displayed in the page zoom drop-down menu
       * as percentages.
       */
      pageZoomLevels_: Array,

      themeSublabel_: String,

      themeUrl_: String,

      useSystemTheme_: {
        type: Boolean,
        value:
            false,  // Can only be true on Linux, but value exists everywhere.
      },

      focusConfig_: {
        type: Object,
        value() {
          const map = new Map();
          if (routes.FONTS) {
            map.set(routes.FONTS.path, '#customize-fonts-subpage-trigger');
          }
          return map;
        },
      },

      showReaderModeOption_: {
        type: Boolean,
        value() {
          return loadTimeData.getBoolean('showReaderModeOption');
        },
      },

      isForcedTheme_: {
        type: Boolean,
        computed: 'computeIsForcedTheme_(' +
            'prefs.autogenerated.theme.policy.color.controlledBy)',
      },

      // <if expr="is_linux and not chromeos and not lacros">
      /**
       * Whether to show the "Custom Chrome Frame" setting.
       */
      showCustomChromeFrame_: {
        type: Boolean,
        value() {
          return loadTimeData.getBoolean('showCustomChromeFrame');
        },
      },
      // </if>

      showManagedThemeDialog_: Boolean,
    };
  }

  static get observers() {
    return [
      'defaultFontSizeChanged_(prefs.webkit.webprefs.default_font_size.value)',
      'themeChanged_(' +
          'prefs.extensions.theme.id.value, useSystemTheme_, isForcedTheme_)',

      // <if expr="is_linux and not chromeos">
      // NOTE: this pref only exists on Linux.
      'useSystemThemePrefChanged_(prefs.extensions.theme.use_system.value)',
      // </if>
    ];
  }

  pageVisibility: AppearancePageVisibility;
  private defaultZoom_: number;
  private isWallpaperPolicyControlled_: boolean;
  private fontSizeOptions_: DropdownMenuOptionList;
  private pageZoomLevels_: number[];
  private themeSublabel_: string;
  private themeUrl_: string;
  private useSystemTheme_: boolean;
  private focusConfig_: Map<string, string>;
  private showReaderModeOption_: boolean;
  private isForcedTheme_: boolean;

  // <if expr="is_linux and not chromeos and not lacros">
  private showCustomChromeFrame_: boolean;
  // </if>

  private showManagedThemeDialog_: boolean;
  private appearanceBrowserProxy_: AppearanceBrowserProxy =
      AppearanceBrowserProxyImpl.getInstance();

  ready() {
    super.ready();

    this.$.defaultFontSize.menuOptions = this.fontSizeOptions_;
    // TODO(dschuyler): Look into adding a listener for the
    // default zoom percent.
    this.appearanceBrowserProxy_.getDefaultZoom().then(zoom => {
      this.defaultZoom_ = zoom;
    });

    this.pageZoomLevels_ =
        JSON.parse(loadTimeData.getString('presetZoomFactors'));
  }

  /** @return A zoom easier read by users. */
  private formatZoom_(zoom: number): number {
    return Math.round(zoom * 100);
  }

  /**
   * @param showHomepage Whether to show home page.
   * @param isNtp Whether to use the NTP as the home page.
   * @param homepageValue If not using NTP, use this URL.
   */
  private getShowHomeSubLabel_(
      showHomepage: boolean, isNtp: boolean, homepageValue: string): string {
    if (!showHomepage) {
      return this.i18n('homeButtonDisabled');
    }
    if (isNtp) {
      return this.i18n('homePageNtp');
    }
    return homepageValue || this.i18n('customWebAddress');
  }

  private onCustomizeFontsTap_() {
    Router.getInstance().navigateTo(routes.FONTS);
  }

  private onDisableExtension_() {
    this.dispatchEvent(new CustomEvent(
        'refresh-pref', {bubbles: true, composed: true, detail: 'homepage'}));
  }

  /**
   * @param value The changed font size slider value.
   */
  private defaultFontSizeChanged_(value: number) {
    // This pref is handled separately in some extensions, but here it is tied
    // to default_font_size (to simplify the UI).
    this.set(
        'prefs.webkit.webprefs.default_fixed_font_size.value',
        value - SIZE_DIFFERENCE_FIXED_STANDARD);
  }

  /**
   * Open URL for either current theme or the theme gallery.
   */
  private openThemeUrl_() {
    window.open(this.themeUrl_ || loadTimeData.getString('themesGalleryUrl'));
  }

  private onUseDefaultTap_() {
    if (this.isForcedTheme_) {
      this.showManagedThemeDialog_ = true;
      return;
    }
    this.appearanceBrowserProxy_.useDefaultTheme();
  }

  // <if expr="is_linux and not chromeos">
  private useSystemThemePrefChanged_(useSystemTheme: boolean) {
    this.useSystemTheme_ = useSystemTheme;
  }

  /** @return Whether to show the "USE CLASSIC" button. */
  private showUseClassic_(themeId: string, useSystemTheme: boolean): boolean {
    return !!themeId || useSystemTheme;
  }

  /** @return Whether to show the "USE GTK+" button. */
  private showUseSystem_(themeId: string, useSystemTheme: boolean): boolean {
    return (!!themeId || !useSystemTheme) &&
        !this.appearanceBrowserProxy_.isChildAccount();
  }

  /**
   * @return Whether to show the secondary area where "USE CLASSIC" and
   *     "USE GTK+" buttons live.
   */
  private showThemesSecondary_(themeId: string, useSystemTheme: boolean):
      boolean {
    return this.showUseClassic_(themeId, useSystemTheme) ||
        this.showUseSystem_(themeId, useSystemTheme);
  }

  private onUseSystemTap_() {
    if (this.isForcedTheme_) {
      this.showManagedThemeDialog_ = true;
      return;
    }
    this.appearanceBrowserProxy_.useSystemTheme();
  }
  // </if>

  private themeChanged_(
      themeId: string, useSystemTheme: boolean, isForcedTheme: boolean) {
    if (this.prefs === undefined || useSystemTheme === undefined) {
      return;
    }

    if (themeId.length > 0 && themeId !== AUTOGENERATED_THEME_ID &&
        !isForcedTheme) {
      assert(!useSystemTheme);

      this.appearanceBrowserProxy_.getThemeInfo(themeId).then(info => {
        this.themeSublabel_ = info.name;
      });

      this.themeUrl_ = 'https://chrome.google.com/webstore/detail/' + themeId;
      return;
    }

    this.themeUrl_ = '';

    if (themeId === AUTOGENERATED_THEME_ID || isForcedTheme) {
      this.themeSublabel_ = this.i18n('chromeColors');
      return;
    }

    let i18nId;
    // <if expr="is_linux and not chromeos and not lacros">
    i18nId = useSystemTheme ? 'systemTheme' : 'classicTheme';
    // </if>
    // <if expr="not is_linux or chromeos_ash or chromeos_lacros">
    i18nId = 'chooseFromWebStore';
    // </if>
    this.themeSublabel_ = this.i18n(i18nId);
  }

  /** @return Whether applied theme is set by policy. */
  private computeIsForcedTheme_(): boolean {
    return !!this.getPref('autogenerated.theme.policy.color').controlledBy;
  }

  private onZoomLevelChange_() {
    chrome.settingsPrivate.setDefaultZoom(parseFloat(this.$.zoomLevel.value));
  }

  /** @see blink::PageZoomValuesEqual(). */
  private zoomValuesEqual_(zoom1: number, zoom2: number): boolean {
    return Math.abs(zoom1 - zoom2) <= 0.001;
  }

  private showHr_(previousIsVisible: boolean, nextIsVisible: boolean): boolean {
    return previousIsVisible && nextIsVisible;
  }

  private onManagedDialogClosed_() {
    this.showManagedThemeDialog_ = false;
  }
}

declare global {
  interface HTMLElementTagNameMap {
    'settings-appearance-page': SettingsAppearancePageElement;
  }
}

customElements.define(
    SettingsAppearancePageElement.is, SettingsAppearancePageElement);
